/**
 * A PrivacyListManager is used by XMPP clients to block or allow communications from other
 * users. Use the manager to: <ul>
 *      <li>Retrieve privacy lists.
 *      <li>Add, remove, and edit privacy lists.
 *      <li>Set, change, or decline active lists.
 *      <li>Set, change, or decline the default list (i.e., the list that is active by default).
 * </ul>
 * Privacy Items can handle different kind of permission communications based on JID, group, 
 * subscription type or globally (@see PrivacyItem).
 * 
 * @author Francisco Vives
 */
class PrivacyListManager {
public:
	
    /**
     * Answer the active privacy list.
     * 
     * @return the privacy list of the active list.
     * @throws XMPPException if an error occurs.
     */ 
    PrivacyList * getActiveList() ;
    
    /**
     * Answer the default privacy list.
     * 
     * @return the privacy list of the default list.
     * @throws XMPPException if an error occurs.
     */ 
    PrivacyList * getDefaultList() ;
    
	/**
	 * Answer the privacy list items under listName with the allowed and blocked permissions.
	 * 
	 * @param listName the name of the list to get the allowed and blocked permissions.
	 * @return a privacy list under the list listName.
     * @throws XMPPException if an error occurs.
	 */ 
	PrivacyList * getPrivacyList(std::string & listName) ;
	
    /**
     * Answer every privacy list with the allowed and blocked permissions.
     * 
     * @return an array of privacy lists.
     * @throws XMPPException if an error occurs.
     */ 
    PrivacyList ** getPrivacyLists() ;
    
	/**
	 * Set or change the active list to listName.
	 * 
	 * @param listName the list name to set as the active one.
	 * @exception XMPPException if the request or the answer failed, it raises an exception.
	 */ 
	void setActiveListName(std::string & listName) ;
	
	/**
	 * Client declines the use of active lists.
     *
     * @throws XMPPException if an error occurs.
	 */ 
	void declineActiveList() ;

	/**
	 * Set or change the default list to listName.
	 * 
	 * @param listName the list name to set as the default one.
	 * @exception XMPPException if the request or the answer failed, it raises an exception.
	 */ 
	void setDefaultListName(std::string & listName) ;
	
	/**
	 * Client declines the use of default lists.
     *
     * @throws XMPPException if an error occurs.
	 */ 
	void declineDefaultList() ;
	
	/**
	 * The client has created a new list. It send the new one to the server.
	 * 
     * @param listName the list that has changed its content.
     * @param privacyItems a List with every privacy item in the list.
     * @throws XMPPException if an error occurs.
	 */ 
	void createPrivacyList(std::string & listName, std::vector<PrivacyItem*> & privacyItems);

    /**
     * The client has edited an existing list. It updates the server content with the resulting 
     * list of privacy items. The {@link PrivacyItem} list MUST contain all elements in the 
     * list (not the "delta").
     * 
     * @param listName the list that has changed its content.
     * @param privacyItems a List with every privacy item in the list.
     * @throws XMPPException if an error occurs.
     */ 
    void updatePrivacyList(std::string & listName, std::vector<PrivacyItem*> & privacyItems);
	    
	/**
	 * Remove a privacy list.
	 * 
     * @param listName the list that has changed its content.
     * @throws XMPPException if an error occurs.
	 */ 
	void deletePrivacyList(std::string & listName) ;
		
    /**
     * Adds a packet listener that will be notified of any new update in the user
     * privacy communication.
     *
     * @param listener a packet listener.
     */
    void addListener(PrivacyListListener * listener) ;

    /**
     * Returns the PrivacyListManager instance associated with a given XMPPConnection.
     * 
     * @param connection the connection used to look for the proper PrivacyListManager.
     * @return the PrivacyListManager associated with a given XMPPConnection.
     */
    static PrivacyListManager * getInstanceFor(XMPPConnection * connection) { return instances.get(connection); }
protected:

private:
	class RmPLManagerListener : public ConnectionListener {
	public:
		void connectionClosed() {
        	// Unregister this instance since the connection has been closed
            instances.remove(connection);
        }

        void connectionClosedOnError(Exception e) {
        	// ignore
        }

        void reconnectionFailed(Exception e) {
        	// ignore
        }

        void reconnectingIn(int seconds) {
        	// ignore
        }

        void reconnectionSuccessful() {
        	// ignore
        }

	};

	class PrivacyListPacketListener : public PacketListener {
	public:
		class AIQ : public IQ {
		public:
			std::string getChildElementXML() {
				return "";
			}
		};
		void processPacket(Packet * packet) {
			
            if (packet == NULL|| packet->getError() != NULL) {
                    return;
            }
            // The packet is correct.
            Privacy * privacy = (Privacy*) packet;
                
            // Notifies the event to the listeners.  TODO---mutex
            
            for (PrivacyListListener listener : listeners) {
                // Notifies the created or updated privacy lists
                for (Map.Entry<String,List<PrivacyItem>> entry : privacy.getItemLists().entrySet()) {
                    String listName = entry.getKey();
                            List<PrivacyItem> items = entry.getValue();
                            if (items.isEmpty()) {
                                listener.updatedPrivacyList(listName);
                            } else {
                                listener.setPrivacyList(listName, items);
                            }
                        }
                    }
                
                
                // Send a result package acknowledging the reception of a privacy package.
                
                // Prepare the IQ packet to send
                IQ * iq = new AIQ() {
                iq->setType(IQ::Type::RESULT);
                iq->setFrom(packet->getFrom());
                iq->setPacketID(packet->getPacketID());

                // Send create & join packet.
                connection->sendPacket(iq);
		}
	};
	/**
     * Creates a new privacy manager to maintain the communication privacy. Note: no
     * information is sent to or received from the server until you attempt to 
     * get or set the privacy communication.<p>
     *
     * @param connection the XMPP connection.
     */
	void PrivacyListManager(XMPPConnection * connection) ;
	
	/** Answer the connection userJID that owns the privacy.
	 * @return the userJID that owns the privacy
	 */
	std::string getUser() { return connection->getUser(); }

    /**
     * Initializes the packet listeners of the connection that will notify for any set privacy 
     * package. 
     */
    void init() ;
    
	/**
	 * Send the {@link Privacy} packet to the server in order to know some privacy content and then 
	 * waits for the answer.
	 * 
	 * @param requestPrivacy is the {@link Privacy} packet configured properly whose XML
     *      will be sent to the server.
	 * @return a new {@link Privacy} with the data received from the server.
	 * @exception XMPPException if the request or the answer failed, it raises an exception.
	 */ 
	Privacy * getRequest(Privacy * requestPrivacy) ;
		
	/**
	 * Send the {@link Privacy} packet to the server in order to modify the server privacy and 
	 * waits for the answer.
	 * 
	 * @param requestPrivacy is the {@link Privacy} packet configured properly whose xml will be sent
	 * to the server.
	 * @return a new {@link Privacy} with the data received from the server.
	 * @exception XMPPException if the request or the answer failed, it raises an exception.
	 */ 
	Packet * setRequest(Privacy * requestPrivacy) ;
	
	/**
	 * Answer a privacy containing the list structre without {@link PrivacyItem}.
	 * 
	 * @return a Privacy with the list names.
     * @throws XMPPException if an error occurs.
	 */ 
	Privacy * getPrivacyWithListNames() ;
    
    /**
     * Answer the privacy list items under listName with the allowed and blocked permissions.
     * 
     * @param listName the name of the list to get the allowed and blocked permissions.
     * @return a list of privacy items under the list listName.
     * @throws XMPPException if an error occurs.
     */ 
	std::vector<PrivacyItem*> getPrivacyListItems( std::string & listName) ;

	static std::map<XMPPConnection*, PrivacyListManager*> instances ;
	XMPPConnection * connection;
	std::vector<PrivacyListListener*> listeners ;
	PacketFilter * packetFilter ;
};
